package com.imooc.user.client;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.gson.Gson;
import com.imooc.dto.UserDTO;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.DefaultServiceUnavailableRetryStrategy;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;

import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeUnit;

/**
 * @Auther: zhaozeyang
 * @Date: 2018/8/29 20:18
 * @Description:
 */
public abstract class LoginFIlter implements Filter {

    private int retryCount = 3;
    private int retryInterval = 5000;
    private Integer defaultMaxPerRoute = 8;

    private static Cache<String, UserDTO> cache = CacheBuilder.newBuilder().maximumSize(10000).expireAfterWrite(3, TimeUnit.MINUTES).build();

    public void init(FilterConfig filterConfig) throws ServletException {

    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;

        String token = httpServletRequest.getParameter("token");
        if (token == null || "".equals(token)) {
            Cookie[] cookies = httpServletRequest.getCookies();
            if (cookies != null) {
                for (Cookie cookie : cookies) {
                    if (cookie.getName().equals("token")) {
                        token = cookie.getValue();
                    }
                }
            }
        }
        UserDTO userDTO = null;
        if (token != null && !"".equals(token)) {
            userDTO = cache.getIfPresent(token);
            if (userDTO == null) {
                userDTO = requestUserInfo(token);
                cache.put(token, userDTO);
            }
        }
        if (userDTO == null) {
            httpServletResponse.sendRedirect("http://127.0.0.1:8082/user/tologin");
            return;
        }
        login(httpServletRequest, httpServletResponse, userDTO);
        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }

    protected abstract void login(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, UserDTO userDTO);

    private UserDTO requestUserInfo(String token) throws IOException {
        InputStream inputStream = null;
        try {
            String url = "http://127.0.0.1:8082/user/auth";
            PoolingHttpClientConnectionManager connectionManager = getHttpClientConnectionManager(defaultMaxPerRoute);

            CloseableHttpClient httpClient = newInstanceUseDefaultRequestLongTimeOutConfig(connectionManager);
            HttpPost httpPost = new HttpPost(url);
            httpPost.addHeader("token", token);
            CloseableHttpResponse response = httpClient.execute(httpPost);
            if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
                throw new RuntimeException();
            }
            inputStream = response.getEntity().getContent();
            byte[] temp = new byte[1024];
            StringBuilder stringBuilder = new StringBuilder();
            int len = 0;
            while ((len = inputStream.read(temp)) > 0) {
                stringBuilder.append(new String(temp, 0, len));
            }
            UserDTO userDTO = new Gson().fromJson(String.valueOf(stringBuilder), UserDTO.class);
            return userDTO;
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }

    public void destroy() {

    }


    /**
     * 加长超时时间的 CloseableHttpClient
     *
     * @param connectionManager
     * @return
     */
    private CloseableHttpClient newInstanceUseDefaultRequestLongTimeOutConfig(PoolingHttpClientConnectionManager connectionManager) {
        //ConnectionRequestTimeout 从连接池中获取链接的超时时间
        //ConnectTimeout  连接建立时间，三次握手完成时间
        //SocketTimeout  数据传输过程中数据包之间间隔的最大时间
        RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(20 * 1000).setConnectTimeout(10 * 1000).setSocketTimeout(30 * 1000).build();

        return HttpClients.custom().setRetryHandler(new DefaultHttpRequestRetryHandler(retryCount, false)).
                setConnectionManager(connectionManager).setServiceUnavailableRetryStrategy(new DefaultServiceUnavailableRetryStrategy(retryCount, retryInterval)).setDefaultRequestConfig(requestConfig)
                .build();

    }

    private PoolingHttpClientConnectionManager getHttpClientConnectionManager(int maxPerRoute) {
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
        cm.setMaxTotal(maxPerRoute);
        cm.setDefaultMaxPerRoute(maxPerRoute);
        return cm;
    }
}
